#include "Avalon/IOTests/PipedReaderWriterTester.hpp"
#include "Avalon/IO/Buffer.hpp"
#include "Avalon/IO/PipedReader.hpp"
#include "Avalon/IO/PipedWriter.hpp"

using namespace Avalon;
using namespace Avalon::IO;
using namespace Avalon::IO::Tests;
using namespace boost;
using namespace boost::posix_time;
using namespace std;

void PipedReaderWriterTester::TestSingleWriteSingleRead() {
  PipedReader reader;
  PipedWriter writer(&reader);
  string message = "hello world";
  writer.Write(message.c_str(), static_cast<int>(message.size()));
  Buffer readData;
  CPPUNIT_ASSERT(reader.Read(&readData)->Get(seconds(1)) == message.size());
  CPPUNIT_ASSERT(readData.GetSize() == message.size());
  CPPUNIT_ASSERT(string(readData.GetData(), readData.GetSize()) == message);
}

void PipedReaderWriterTester::TestMultipleWriteSingleRead() {
  PipedReader reader;
  PipedWriter writer(&reader);
  string firstFragment = "hello";
  string secondFragment = " world";
  string message = firstFragment + secondFragment;
  writer.Write(firstFragment.c_str(), static_cast<int>(firstFragment.size()));
  writer.Write(secondFragment.c_str(), static_cast<int>(secondFragment.size()));
  Buffer readData;
  CPPUNIT_ASSERT(reader.Read(&readData)->Get(seconds(1)) == message.size());
  CPPUNIT_ASSERT(readData.GetSize() == message.size());
  CPPUNIT_ASSERT(string(readData.GetData(), readData.GetSize()) == message);
}

void PipedReaderWriterTester::TestMultipleWriteRead() {
  PipedReader reader;
  PipedWriter writer(&reader);
  string firstFragment = "hello";
  string secondFragment = " world";

  // Write then read the first fragment.
  writer.Write(firstFragment.c_str(), static_cast<int>(firstFragment.size()));
  Buffer readData;
  CPPUNIT_ASSERT(reader.Read(&readData)->Get(seconds(1)) ==
    firstFragment.size());
  CPPUNIT_ASSERT(readData.GetSize() == firstFragment.size());
  CPPUNIT_ASSERT(string(readData.GetData(), readData.GetSize()) ==
    firstFragment);

  // Write and read the second fragment.
  writer.Write(secondFragment.c_str(), static_cast<int>(secondFragment.size()));
  readData.Reset();
  CPPUNIT_ASSERT(reader.Read(&readData)->Get(seconds(1)) ==
    secondFragment.size());
  CPPUNIT_ASSERT(readData.GetSize() == secondFragment.size());
  CPPUNIT_ASSERT(string(readData.GetData(), readData.GetSize()) ==
    secondFragment);
}

void PipedReaderWriterTester::TestMultipleWritesThenMultipleReads() {
  PipedReader reader;
  PipedWriter writer(&reader);
  string firstFragment = "hello";
  string secondFragment = " world";

  // Write both fragments.
  writer.Write(firstFragment.c_str(), static_cast<int>(firstFragment.size()));
  writer.Write(secondFragment.c_str(), static_cast<int>(secondFragment.size()));

  // Read the first fragment.
  Buffer firstFragmentRead;
  CPPUNIT_ASSERT(reader.Read(&firstFragmentRead,
    static_cast<int>(firstFragment.size()))->Get(seconds(1)) ==
    firstFragment.size());
  CPPUNIT_ASSERT(firstFragmentRead.GetSize() == firstFragment.size());
  CPPUNIT_ASSERT(string(firstFragmentRead.GetData(), firstFragment.size()) ==
    firstFragment);

  // Read the second fragment.
  Buffer secondFragmentRead;
  CPPUNIT_ASSERT(reader.Read(&secondFragmentRead,
    static_cast<int>(secondFragment.size()))->Get(seconds(1)) ==
    secondFragment.size());
  CPPUNIT_ASSERT(secondFragmentRead.GetSize() == secondFragment.size());
  CPPUNIT_ASSERT(string(secondFragmentRead.GetData(),
    secondFragmentRead.GetSize()) == secondFragment);
}
